<?php
/**
 * Created by PhpStorm.
 * User: denh
 * Date: 16/5/22
 * Time: 上午11:17
 */

abstract class DataObject extends Base
{
    public $data; //hash array
    public $has_loaded; //是否已经从数据库加载

    private $where;
    private $fields;
    private $leftJoin;
    private $leftJoinAlias;
    private $on;
    private $orderby;
    private $offset;
    private $limit;
    private $groupby;
    private $having;
    public $sql;
    private $like;

    public function __construct()
    {
        parent::__construct();
        $this->has_loaded = false;
        $data = array();

    }


    public function field_exists($field_name)
    {
        $r = self::$pdo->query("DESCRIBE " . $this->tableName() . " `{$field_name}`");

        return !empty($r);
    }


    /**
     * @return string|bool
     * 所有的子类都需要自己返回表名函数
     * 不是独立表的return false
     */
    abstract function tableName();

    /**
     * 得到列名，返回numed array 例子: array('id','openid'..)
     * @return bool
     * 列名是否存在
     */
    public function  get_fields()
    {
        $sql = " SELECT `column_name` FROM `information_schema`.columns";
        $wheres = array('table_name' => $this->tableName());

        return self::$pdo->selectAll($sql, $wheres, PDO::FETCH_NUM);
    }


    /**
     *
     * @param array $columns
     * @return bool|mixed
     */
    public function loadColumns(array $columns)
    {
        $r = self::$pdo->selectColumns($this->tableName(), $columns, $this->data);
        $this->set属性数组($r);
        return $r;
    }


    /**
     *
     * 得到$columns指定列,并修改this数据
     * 不会影响has_loaded状态
     */
    public function set属性数组( $values)
    {
        // Linhe::tools()->array2object($values, $this);
        //$this->data=array_replace($this->data, $values);
        $this->data = $values;
    }

    /**
     * @return array
     * 返回data数组
     */
    public function get属性数组()
    {
        return $this->data;
    }

    //将array赋值给当前的对象
    //操作：写类数据

    /**
     * 根据现有赋值从数据库取
     * @param $id
     * @return bool
     */
    function loadById($id)
    {
        return $this->loadByKeys(array('id' => $id));
    }

    /**
     * 成功： has_loaded = true 否则 = false
     * 失败：没有记录或多条记录都认为是失败
     * @param array $keys 数据库主键，或者联合主键
     * @return bool
     */
    public function loadByKeys($keys)
    {

        $this->has_loaded = false;
        $sql = " SELECT * FROM" . " " . $this->tableName();
        $array = self::$pdo->selectOne($sql, $keys);
        if ($array) {   //有且仅有一条记录
            $this->set属性数组($array);
            $this->has_loaded = true;
            return true;
        }

        return false; //没有数据
    }

    /**
     * 从数据库读取记录: 查询条件为赋过值的属性
     * @return bool
     */
    public function loadFromDB(){
        return $this->loadByKeys($this->data);
    }

    //todo 测试是否支持多次fech，如果不支持，需要设置pdo成mysql及相关参数
    //操作：1、读数据库 2、写类数据 3、修改has_loaded
    /**
     * DO保存到数据库
     * @return int
     */
    function  save()
    {
        if (array_key_exists('id',$this->data)){
            if (!empty($this->data['id'])) {
                $ret= $this->update();
                if ($ret === 0) $ret=true; //如果数据和原有的相同,则返回0不表示更新失败, 只是表示更新了0条数据
                return $ret;
            }
        }

        $ret= self::$pdo->insert($this->tableName(), $this->data);
        if($ret) $this->data['id']=self::$pdo->lastInsertId();
        return $ret;
    }

    /**
     * @param array $where
     * @return bool|int 返回更新的行数
     */
    public function  update($where = array())
    {
        if (!$where) {
            $where = array('id' => $this->getId());
        }
        return self::$pdo->update($this->tableName(), $this->data, $where);
    }

    /**
     * @return int
     */
    public function getId()
    {
        return $this->data['id'];
    }

    function insert(){
        return self::$pdo->insert($this->tableName(), $this->data);
    }

    /**
     * @return bool|int
     * 只有id赋值的才能调用该函数
     */
    public function delete()
    {
        if (!$this->getId())
            return false;
        $conditions = array('id' => $this->getId());
        return self::$pdo->delete($this->tableName(), $conditions);
    }

    /**
     * @return mixed 返回记录总数（只支持查询一张表）
     */
    public function count() {
        $this->sql = $this->sql(true);
        $data = self::$pdo->selectOne($this->sql);
        return reset($data);
    }

 

    public function where($where) {
        if (is_array($where)) {
            foreach ($where as $k => $v) {
                $w[] = "$k = '$v'";
            }
            $this->where = implode(' and ', $w);
        } else {
            $this->where = $where;
        }
        return $this;
    }



    #多个字段用逗号隔开
    public function fields($fields) {
        if (!is_array($fields)) {
            $fields = explode(',', $fields);
        }
        $fields = array_unique($fields);
        $this->fields = implode(',', $fields);
        return $this;
    }

    public function orderby($orderby) {
        $this->orderby = $orderby;
        return $this;
    }

    public function groupby($groupby, $having = '') {
        $this->groupby = $groupby;
        $this->having = $having;
        return $this;
    }

    public function offset($offset) {
        $this->offset = $offset;
        return $this;
    }

    public function limit($limit) {
        $this->limit = $limit;
        return $this;
    }

    /**
     * @param string $id
     * @return array[]|bool 返回多行记录
     */
    public function rows($id = '') {
        if (is_numeric($id)) {
            $this->where = "where id = '$id'";
        }
        $sql = $this->sql();
        if (!$this->offset) $this->offset = 0;
        if ($this->limit) $sql .= " limit $this->offset, $this->limit";
        $this->sql = $sql;
        $data = self::$pdo->selects($sql);
        return $data;
    }

    /**
     * @param string $id
     * @return $this|bool 返回单行记录
     */
    public function row($id='') {
        if (is_numeric($id)) {
            $this->where = "id = '$id'";
        }
        $sql = $this->sql();
        $sql .= " limit 1";
        $this->sql = $sql;
        $data = self::$pdo->selectOne($sql);
        if ($data) {   //有且仅有一条记录
            $this->set属性数组($data);
            $this->has_loaded = true;
            return $this;
        }
        return false; //没有数据
    }

    /**
     * @return bool|mixed 返回单字段值
     */
    public function getOneField() {
        $sql = $this->sql();
        $sql .= " limit 1";
        $this->sql = $sql;
        $data = self::$pdo->selectOne($sql);
        if (!$data) {
            return false;
        }
        return reset($data);
    }

    private function sql($count = false) {
        $tableName = $this->tableName();
        if (!$this->fields) $this->fields = '*';
        if ($count) {
            $sql = "select count(*) from $tableName a";
        } else {
            $sql = "select $this->fields from $tableName a";
        }
        if ($this->leftJoin) {
            foreach ($this->leftJoin as $k => $v) {
                $sql .=  sprintf(" left join %s %s on %s",
                    $this->leftJoin[$k], $this->leftJoinAlias[$k], $this->on[$k]);
            }
        }
        if ($this->where) $sql .= " where $this->where";
        if ($this->groupby) {
            $sql .= " group by $this->groupby";
            if ($this->having) $sql .= " having $this->having";
        }
        if ($this->orderby) $sql .= " order by $this->orderby";
        $this->sql = $sql;
        return $sql;
    }

    /**
     * @param DataObject $do 左连接表数据对象
     * @param String $alias 左连接表别名
     * @param String $on 连接条件
     * @return $this
     */
    public function leftJoin(DataObject $do, $alias, $on = '') {
        $this->leftJoin[] = $do->tableName();
        $this->leftJoinAlias[] = $alias;
        if ($on) $this->on[] = $on;
        return $this;
    }

    /**
     * @param String $on 左连接条件
     * @return $this
     */
    public function on($on) {
        $this->on[] = $on;
        return $this;
    }

    function __destruct() {
        if ($this->sql) {
            logger()->logInfo(sprintf("dbBase sql:[%s]", $this->sql));
        }
    }


}
